﻿using System;
using System.Collections.ObjectModel;
using System.Windows;
using Plugins.Core;
using Plugins.Historical;
using StockModel;
using Plugins;
using Utils;
using Utils.Wpf;

namespace StockAnalyst2.Plugins.Visualization.Historical
{
	internal class HistoricalPluginViewerVM : ViewModelBase, IDisposable
	{
		#region Attributes

		private bool _isVisible;
		private IStrategyPlugin _plugin;
		private readonly ExecutionResultStatisticsCalculator _statisticsCalculator;

		#endregion

		#region Properties

		public bool IsVisible
		{
			get
			{
				return _isVisible;
			}
			set
			{
				if (_isVisible != value)
				{
					_isVisible = value;
					base.OnPropertyChanged("IsVisible");
				}
			}
		}

		public IStrategyPlugin Plugin
		{
			get
			{
				return _plugin;
			}
			set
			{
				if (_plugin != value)
				{
					if (_plugin != null)
					{
						_plugin.HistoricalResultsAvailable -= this.PluginHistoricalResultsAvailable;
						_plugin.HistoricalControlPanel.Visibility = Visibility.Collapsed;
					}
					
					this.Result.Clear();
					_plugin = value;
					_plugin.HistoricalResultsAvailable += this.PluginHistoricalResultsAvailable; // Disposed
					base.OnPropertyChanged("Plugin");
					_plugin.HistoricalControlPanel.Visibility = Visibility.Visible;
				}
			}
		}

		public ObservableCollection2<Operation> Result { get; private set; }
		public ObservableCollection<FrameworkElement> CustomPluginData { get; private set; }
		public ResultViewerVM ResultViewerVM { get; private set; }

		#endregion

		#region Public Methods

		public HistoricalPluginViewerVM()
		{
			_statisticsCalculator = new ExecutionResultStatisticsCalculator();

			this.Result = new ObservableCollection2<Operation>();
			this.CustomPluginData = new ObservableCollection<FrameworkElement>();
			this.ResultViewerVM = new ResultViewerVM(_statisticsCalculator.Statistics, this.Result, this.CustomPluginData);
		}

		#endregion

		#region Event Handlers

		private void PluginHistoricalResultsAvailable(object sender, HistoricalResultsAvailableEventArgs e)
		{
			// All the operations here have to be processed by the main thread and there is no work to be done to prepare the data
			// so its safe to execute everything on the MainUI thread.
			if (base.Dispatcher.CheckAccess())
			{
				_statisticsCalculator.CalculateStatistics(e.Result);

				this.Result.Clear();
				this.Result.AddRange(e.Result.Operations);
				this.CustomPluginData.Clear();

				foreach (FrameworkElement uiElement in e.CustomData)
				{
					this.CustomPluginData.Add(uiElement);
				}
			}
			else
			{
				base.Dispatcher.Invoke(new Action<object, HistoricalResultsAvailableEventArgs>(this.PluginHistoricalResultsAvailable), new object[] { sender, e });
			}
		}

		#endregion

		#region IDisposable

		protected bool Disposed { get; private set; }

		private void Dispose(bool disposing)
		{
			if (!this.Disposed)
			{
				this.InternalDispose(disposing);
			}

			this.Disposed = true;
		}

		protected virtual void InternalDispose(bool disposing)
		{
			if (disposing)
			{
				this.ResultViewerVM.Dispose();

				if (_plugin != null)
				{
					_plugin.HistoricalResultsAvailable -= PluginHistoricalResultsAvailable;
				}
			}

			// Dispose here only unmanaged objects 
			// Don’t use managed objects here because maybe 
			// they have been finalized already
		}

		public void Dispose()
		{
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}

		~HistoricalPluginViewerVM()
		{
			this.Dispose(false);
		}

		#endregion

	}
}
